package quan.dong.common;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.URL;
import java.net.UnknownHostException;

public class TCPSocket {

	final int SEND_BUFFER_SIZE = 1452; // ethernet packet 1500 - 40 tcp/ip
										// header - 8 PPPoE info = 1452

	public Socket _mySocKet;
	private OutputStream _outputStream;
	private DataInputStream _dataInputStream;
	private byte[] _sendBuffer = new byte[3000];
	private int _sendBufferLen = 0;
	
	public TCPSocket() {
		super();
		try {
			this._dataInputStream = null;
			this._outputStream = null;
		} catch (Exception e) {
			e.getStackTrace();
		}
	}

	public boolean Create(String hostName, int port) {
		try {

			InetAddress addr = InetAddress.getByName(hostName);
			SocketAddress sockaddr = new InetSocketAddress(addr, port);
			this._mySocKet = new Socket();
			int timeoutMs = 30000; // 2 seconds
			this._mySocKet.connect(sockaddr, timeoutMs);
			_dataInputStream = new DataInputStream (new BufferedInputStream(
					_mySocKet.getInputStream()));
			_outputStream = _mySocKet.getOutputStream();

			return true;
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			// e.printStackTrace();
			return false;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			// e.printStackTrace();
			return false;
		}
	}

	public Socket get_mySocKet() {
		return _mySocKet;
	}

	public boolean Close() {
		try {
			if (this._mySocKet.getInputStream() != null)
				this._mySocKet.shutdownInput();
			if (this._mySocKet.getOutputStream() != null)
				this._mySocKet.shutdownOutput();
			this._dataInputStream = null;
			this._outputStream = null;
			if (this._mySocKet.isClosed() == false)
				this._mySocKet.close();
			this._mySocKet = null;
			return true;
		} catch (Exception ex) {
			// Log.i("Close Socket Erro", ex.getMessage());
			return false;
		}
	}

	public boolean ShutDown() {
		try {
			if (this._mySocKet.getInputStream() != null)
				this._mySocKet.shutdownInput();
			if (this._mySocKet.getOutputStream() != null)
				this._mySocKet.shutdownOutput();
			return true;
		} catch (Exception ex) {
			// Log.i("Close Socket Erro", ex.getMessage());
			return false;
		}
	}

	private long SendData(byte[] buffer, int offset, int sendLen) {
		try {

			// this._outputStream = this._mySocKet.getOutputStream();
			// this._dataOutputStream = new DataOutputStream(
			// this._outputStream);
			// this._dataOutputStream.write(buffer, 0, buffer.length);
			// this._dataOutputStream.flush();
			_outputStream.write(buffer, offset, sendLen);
			_outputStream.flush();
		} catch (IOException ex) {
			// Log.i("Send data Socket IOException Erro", ex.getMessage());
			return 0;
		} catch (Exception ex) {
			// Log.i("Send data Socket Erro", ex.getMessage());
			return 0;
		}
		return sendLen;
	}

	private int SendQueued(byte[] buffer, int sendLen) {
		// Ghi buffer vao hang doi. Neu hang doi day thi gui het hang doi
		int newsize = _sendBufferLen + sendLen;
		int byteToSend = sendLen;
		int bufferOffset = 0;

		if (newsize >= SEND_BUFFER_SIZE) {
			System.arraycopy(buffer, bufferOffset, _sendBuffer, _sendBufferLen,
					SEND_BUFFER_SIZE - _sendBufferLen);
			// Log.i("Leng read in socket"," "+leng);
			if (SendData(_sendBuffer, 0, SEND_BUFFER_SIZE) == 0)
				return 0;

			bufferOffset += (SEND_BUFFER_SIZE - _sendBufferLen);
			byteToSend -= (SEND_BUFFER_SIZE - _sendBufferLen);
			_sendBufferLen = 0;

			while (byteToSend >= SEND_BUFFER_SIZE) {
				if (SendData(buffer, bufferOffset, SEND_BUFFER_SIZE) == 0)
					return 0;

				bufferOffset += SEND_BUFFER_SIZE;
				byteToSend -= SEND_BUFFER_SIZE;
			}
		}

		// con du lieu thi ghi vao hang doi
		System.arraycopy(buffer, bufferOffset, _sendBuffer, _sendBufferLen,
				byteToSend);
		_sendBufferLen += byteToSend;
		return sendLen;
	}

	private int SendFlush(byte[] buffer, int sendLen) throws Exception {
		// SendQueued(buffer, sendLen);
		// Ghi buffer vao hang doi. Neu hang doi day thi gui het hang doi
		int newsize = _sendBufferLen + sendLen;
		int byteToSend = sendLen;
		int bufferOffset = 0;

		if (newsize >= SEND_BUFFER_SIZE) {
			System.arraycopy(buffer, bufferOffset, _sendBuffer, _sendBufferLen,
					SEND_BUFFER_SIZE - _sendBufferLen);
			// Log.i("Leng read in socket"," "+leng);
			if (SendData(_sendBuffer, 0, SEND_BUFFER_SIZE) == 0)
				return 0;

			bufferOffset += (SEND_BUFFER_SIZE - _sendBufferLen);
			byteToSend -= (SEND_BUFFER_SIZE - _sendBufferLen);
			_sendBufferLen = 0;

			while (byteToSend >= SEND_BUFFER_SIZE) {
				if (SendData(buffer, bufferOffset, SEND_BUFFER_SIZE) == 0)
					return 0;

				bufferOffset += SEND_BUFFER_SIZE;
				byteToSend -= SEND_BUFFER_SIZE;
			}
		}

		// con du lieu thi ghi vao hang doi
		System.arraycopy(buffer, bufferOffset, _sendBuffer, _sendBufferLen,
				byteToSend);
		_sendBufferLen += byteToSend;

		// Con du lieu tron hang doi, gui het
		if (_sendBufferLen > 0) {
			if (SendData(_sendBuffer, 0, _sendBufferLen) == 0)
				return 0;
		}
		_sendBufferLen = 0;
		return sendLen;
	}

	public boolean SendExactQueue(byte[] buffer) throws Exception {
		int result = SendQueued(buffer, buffer.length);
		return result == buffer.length;
	}

	public boolean SendExact(byte[] buffer) throws Exception {
		int result = SendFlush(buffer, buffer.length);
		return result == buffer.length;
	}

	public boolean SendExactQueue(byte[] buffer, int sendLen) throws Exception {
		int result = SendQueued(buffer, sendLen);
		return result == sendLen;
	}

	public boolean SendExact(byte[] buffer, int sendLen) throws Exception {
		int result = SendFlush(buffer, sendLen);
		return result == sendLen;
	}

	public boolean FlushSendQueue() throws Exception {
		if (_sendBufferLen > 0) {
			if (SendData(_sendBuffer, 0, _sendBufferLen) == 0)
				return false;
			_sendBufferLen = 0;
		}
		return true;
	}

	public void ReadExact(byte[] buffer, int offset, int readLen)
			throws Exception {
		//int a=_dataInputStream.read(buffer, offset, readLen);	
		_dataInputStream.readFully(buffer, offset, readLen);
	}
	
	public void ReadExact(byte[] buffer, int readLen) throws Exception {
		ReadExact(buffer, 0, readLen);
	}
	
	public void ReadExact(byte[] buffer) throws Exception {
		ReadExact(buffer, 0, buffer.length);
	}
	 public String getIp() throws Exception {
	        URL whatismyip = new URL("http://checkip.amazonaws.com");
	        BufferedReader in = null;
	        try {
	            in = new BufferedReader(new InputStreamReader(
	                    whatismyip.openStream()));
	            String ip = in.readLine();
	            return ip;
	        } finally {
	            if (in != null) {
	                try {
	                    in.close();
	                } catch (IOException e) {
	                    e.printStackTrace();
	                }
	            }
	        }
	    }
}
